
/*
 * Copyright (C) Igor Sysoev
 * Copyright (C) Nginx, Inc.
 */


#include <ngx_config.h>
#include <ngx_core.h>


#if ((__i386__ || __amd64__) && (__GNUC__ || __INTEL_COMPILER))


static ngx_inline void ngx_cpuid(uint32_t i, uint32_t *buf);


#if (__i386__)

static ngx_inline void
ngx_cpuid(uint32_t i, uint32_t *buf)
{
    /*
     * we could not use %ebx as output parameter if gcc builds PIC,
     * and we could not save %ebx on stack, because %esp is used,
     * when the -fomit-frame-pointer optimization is specified.
     */

    __asm__(

        "    mov    %%ebx, %%esi;  "

        "    cpuid;                "
        "    mov    %%eax, (%1);   "
        "    mov    %%ebx, 4(%1);  "
        "    mov    %%edx, 8(%1);  "
        "    mov    %%ecx, 12(%1); "

        "    mov    %%esi, %%ebx;  "

        :
        : "a"(i), "D"(buf)
        : "ecx", "edx", "esi", "memory");
}


#else /* __amd64__ */


static ngx_inline void
ngx_cpuid(uint32_t i, uint32_t *buf)
{
    uint32_t eax, ebx, ecx, edx;

    __asm__(

        "cpuid"

        : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx)
        : "a"(i));

    buf[0] = eax;
    buf[1] = ebx;
    buf[2] = edx;
    buf[3] = ecx;
}


#endif


/* auto detect the L2 cache line size of modern and widespread CPUs */

void
ngx_cpuinfo(void)
{
    u_char  *vendor;
    uint32_t vbuf[5], cpu[4], model;

    vbuf[0] = 0;
    vbuf[1] = 0;
    vbuf[2] = 0;
    vbuf[3] = 0;
    vbuf[4] = 0;

    ngx_cpuid(0, vbuf);

    vendor = (u_char *)&vbuf[1];

    if (vbuf[0] == 0)
    {
        return;
    }

    ngx_cpuid(1, cpu);

    if (ngx_strcmp(vendor, "GenuineIntel") == 0)
    {
        switch ((cpu[0] & 0xf00) >> 8)
        {
        /* Pentium */
        case 5: ngx_cacheline_size = 32; break;

        /* Pentium Pro, II, III */
        case 6:
            ngx_cacheline_size = 32;

            model = ((cpu[0] & 0xf0000) >> 8) | (cpu[0] & 0xf0);

            if (model >= 0xd0)
            {
                /* Intel Core, Core 2, Atom */
                ngx_cacheline_size = 64;
            }

            break;

        /*
         * Pentium 4, although its cache line size is 64 bytes,
         * it prefetches up to two cache lines during memory read
         */
        case 15: ngx_cacheline_size = 128; break;
        }
    }
    else if (ngx_strcmp(vendor, "AuthenticAMD") == 0)
    {
        ngx_cacheline_size = 64;
    }
}

#else


void
ngx_cpuinfo(void)
{
}


#endif
